package fr.inria.phoenix.diasuite.framework.context.cookerstatus;

import fr.inria.diagen.core.ServiceConfiguration;
import fr.inria.diagen.core.exception.InvocationException;
import fr.inria.diagen.core.network.RemoteServiceInfo;
import fr.inria.diagen.core.service.local.Service;
import fr.inria.diagen.core.service.proxy.Proxy;

import fr.inria.phoenix.diasuite.framework.context.alert.AlertValue;

/**
 * <pre>
context CookerStatus as CookerStatus{
 * 	when provided Alert get CookerReady
 * 	maybe publish;
 * }
</pre>
 */
@SuppressWarnings("all")
public abstract class AbstractCookerStatus extends Service {
    
    public AbstractCookerStatus(ServiceConfiguration serviceConfiguration) {
        super("/Context/CookerStatus/", serviceConfiguration);
    }
    
    // Methods from the Service class
    @Override
    protected final void internalPostInitialize() {
        subscribeValue("alert", "/Context/Alert/"); // subscribe to Alert context
        postInitialize();
    }
    
    @Override
    public final void valueReceived(java.util.Map<String, Object> properties, RemoteServiceInfo source, String eventName, Object value, Object... indexes) {
        if (eventName.equals("alert") && source.isCompatible("/Context/Alert/")) {
            AlertValue alertValue = new AlertValue((java.lang.Boolean) value);
            
            CookerStatusValuePublishable returnValue = onAlert(alertValue, new DiscoverForAlert());
            if(returnValue != null && returnValue.doPublish()) {
                setCookerStatus(returnValue.getValue());
            }
        }
    }
    
    @Override
    public final Object getValueCalled(java.util.Map<String, Object> properties, RemoteServiceInfo source, String valueName,
            Object... indexes) throws Exception {
        if (valueName.equals("cookerStatus")) {
            return getLastValue();
        }
        throw new InvocationException("Unsupported method call: " + valueName);
    }
    // End of methods from the Service class
    
    // Code relative to the return value of the context
    private fr.inria.phoenix.diasuite.framework.datatype.cookerstatus.CookerStatus contextValue;
    
    private void setCookerStatus(fr.inria.phoenix.diasuite.framework.datatype.cookerstatus.CookerStatus newContextValue) {
        contextValue = newContextValue;
        getProcessor().publishValue(getOutProperties(), "cookerStatus", newContextValue);
    }
    
    /**
     * Get the last value of the context
     * 
     * @return the latest value published by the context
     */
    protected final fr.inria.phoenix.diasuite.framework.datatype.cookerstatus.CookerStatus getLastValue() {
        return contextValue;
    }
    
    /**
     * A class that represents a value that might be published for the <code>CookerStatus</code> context. It is used by
     * event methods that might or might not publish values for this context.
     */
    protected final static class CookerStatusValuePublishable {
        
        // The value of the context
        private fr.inria.phoenix.diasuite.framework.datatype.cookerstatus.CookerStatus value;
        // Whether the value should be published or not
        private boolean doPublish;
        
        public CookerStatusValuePublishable(fr.inria.phoenix.diasuite.framework.datatype.cookerstatus.CookerStatus value, boolean doPublish) {
            this.value = value;
            this.doPublish = doPublish;
        }
        
        /**
         * @return the value of the context that might be published
         */
        public fr.inria.phoenix.diasuite.framework.datatype.cookerstatus.CookerStatus getValue() {
            return value;
        }
        
        /**
         * Sets the value that might be published
         * 
         * @param value the value that will be published if {@link #doPublish()} returns true
         */
        public void setValue(fr.inria.phoenix.diasuite.framework.datatype.cookerstatus.CookerStatus value) {
            this.value = value;
        }
        
        /**
         * @return true if the value should be published
         */
        public boolean doPublish() {
            return doPublish;
        }
        
        /**
         * Set the value to be publishable or not
         * 
         * @param doPublish if true, the value will be published
         */
        public void setDoPublish(boolean doPublish) {
            this.doPublish = doPublish;
        }
    }
    // End of code relative to the return value of the context
    
    // Interaction contract implementation
    /**
     * This method is called when the <code>Alert</code> context publishes a value.
    
    <pre>
    when provided Alert get CookerReady
     * 	maybe publish;
    </pre>
     * 
     * @param alertValue the value of the <code>Alert</code> context.
     * @param discover a discover object to get value from devices and contexts
     * @return a {@link CookerStatusValuePublishable} that says if the context should publish a value and which value it should publish
     */
    protected abstract CookerStatusValuePublishable onAlert(AlertValue alertValue, DiscoverForAlert discover);
    
    // End of interaction contract implementation
    
    // Discover object for Alert
    /**
     * An object to discover devices and contexts for the following interaction contract:
     * 
     * <code>
     * when provided Alert get CookerReady
     * 	maybe publish;
     * </code>
     */
    protected final class DiscoverForAlert {
        private final fr.inria.diagen.core.service.filter.service.ServiceFilter cookerReadyFilter = new fr.inria.diagen.core.service.filter.service.ServiceFilter("/Context/CookerReady/");
        
        private RemoteServiceInfo getCookerReadyRsi() {
            return getProcessor().discoverComponents(getOutProperties(), cookerReadyFilter).get(0);
        }
        
        /**
         * Get the value of the <code>CookerReady</code> context
         * 
         * @return the value of the <code>CookerReady</code> context
         */
        public java.lang.Boolean cookerReady() {
            return (java.lang.Boolean) getProcessor().callGetValue(getOutProperties(), getCookerReadyRsi(), "cookerReady");
        }
    }
    // End of discover object for Alert
}
